<?php
declare (strict_types=1);

namespace addons\Builder\driver;

use addons\Builder\facade\Builder;
use app\common\tool\Result;
use think\App;
use think\Exception;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\facade\View;
use think\Response;
use think\response\Json;
use think\Validate;

abstract class TableBase
{

    /**
     * Request实例
     * @var \think\Request
     */
    protected $request;

    /**
     * 应用实例
     * @var \think\App
     */
    protected $app;

    /**
     * 搜索
     * @var \think\App
     */
    protected $search;

    /**
     * 是否批量验证
     * @var bool
     */
    protected $batchValidate = false;

    /**
     * 系统参数
     * @var array
     */
    protected $system;

    /**
     * 管理员信息
     * @var object
     */
    protected $admin;

    /**
     * 表格缓存信息
     * @var object
     */
    protected $tableCache;


    public function __construct(App $app)
    {
        $this->app = $app;
        $this->request = $this->app->request;
        
        $this->tableCache = Builder::TableCache();

        // 控制器初始化
        $this->initialize();

    }

    public function initialize()
    {
        $this->admin = $this->request->admin;
        View::assign([
            'nav'    => $this->request->nav,
            '_admin' => $this->admin,
            'action' => $this->request->action,
        ]);
    }

    /**
     * 原点 2021年7月27日17:22:29 获取相关数据
     */
    public function getList(): Response
    {
        $param = $this->request->get();
        $tableCache = $this->tableCache->getData($param['tableUniqueStr']);
        if (empty($tableCache)) throw new \Exception('页面加载失败，请尝试刷新页面后重试！');
        $ons = ['hasOne', 'append'];
        foreach ($ons as $v) {
            $tableCache[$v] = !empty($this->$v) ? $this->$v : [];
        }
        //定义排序
        $tableCache['sort'] = !empty($this->sort) ? $this->tableCache->getSort($param['tableUniqueStr'], $this->sort) : [];
        //简易钩子函数
        $tableCache['takeOver'] = !empty($this->takeOver) ? $this->takeOver : 0;
        //检测是否查询软删除的数据
        $tableCache['withTrashed'] = !empty($this->withTrashed) ? true : false;
        //检测是否只查询软删除的数据
        $tableCache['onlyTrashed'] = !empty($this->onlyTrashed) ? true : false;
        return Result::fastReturn($this->model::getTableList($tableCache, $param, '*', $this->model));
    }


    /**
     * 原点 2021年7月27日11:05:32 公共添加方法
     */
    public function add($tpl = 'form/add')
    {
        try {
            if (!$this->allowVerify()) $this->error('暂无权限');
            if ($tpl == 'form/add') {
                $tpl = $this->tableCache->getView('add');
            }
            $tableData = $this->tableCache->getData();

            return View::fetch($tpl, [
                'demo_time' => time(),
                'field'     => $this->tableCache->getModify(),
                'backUrl'   => request()->param('back', ''),
                'unite'     => $this->tableCache->getModify('unite'),
                'hideField' => $tableData ? $tableData['extra_map'] : []
            ]);

        } catch (\Exception $e) {

            return $e->getMessage();
        }
    }

    /**
     * 原点 2021年7月27日11:05:32 公共修改方法
     */
    public function edit($id = '', $tpl = 'form/edit', $info = '')
    {
        try {
            if (!$this->allowVerify()) $this->error('暂无权限');
            if ($tpl == 'form/edit') {
                $tpl = $this->tableCache->getView('edit');
            }
            return View::fetch($tpl, [
                'demo_time' => time(),
                'field'     => $this->tableCache->getModify('edit'),
                'backUrl'   => request()->param('back', ''),
                'unite'     => $this->tableCache->getModify('unite'),
                'info'      => $info ?: $this->model::where($this->pk, $id)->find()
            ]);
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    /**
     * @param array $param -- 新增或修改的数据，支持直接调用和间接调用
     * @param array $model -- 调用model方法，默认false
     *
     * 原点 2021年7月27日14:46:07 公共新增/修改方法
     */
    public function save($param = [], $model = false): Json
    {
        if (!$this->allowVerify()) return json(['code' => -1, 'msg' => '无权限']);

        $param = empty($param) ? $this->request->post() : $param;
        if (!isset($param[$this->pk]) && isset($this->validate)) {
            try {
                $this->validate($param, $this->validate);
            } catch (ValidateException $e) {
                return json(['code' => -1, 'msg' => $e->getError()]);
            }
        }
        $action = $model ? '_save' : '_magic';
        return json($this->model::$action($param, $this->getLogsArguments($param, 1)));
    }

    /**
     * 原点 2021年7月27日14:46:29 公共修改字段方法
     */
    public function update(): Json
    {
        try {
            if (!$this->allowVerify()) return json(['code' => -1, 'msg' => '无权限']);
            $param = $this->request->param();
            return json($this->model::_update($param, $this->getLogsArguments($param)));
        } catch (\Exception $e) {
            return json(['code' => -1, 'msg' => $e->getMessage()]);
        }
    }

    /**
     * 原点 2021年7月27日14:46:29 公共删除方法
     */
    public function delete(): Json
    {
        try {
            if (!$this->allowVerify()) return json(['code' => -1, 'msg' => '无权限']);
            $param = $this->request->param();
            return json($this->model::_delete($param, $this->getLogsArguments($param)));
        } catch (\Exception $e) {
            return json(['code' => -1, 'msg' => $e->getMessage()]);
        }
    }

    public function getLogsArguments($param, $type = ''): array
    {
        $data = [
            'pk'               => $this->pk,
            'tableUniqueTitle' => isset($param['tableUniqueTitle']) ? $param['tableUniqueTitle'] : '',
            'admin'            => $this->admin,
            'writeLog'         => isset($this->writeLog) ? $this->writeLog : 1,
            'writeLogKey'      => isset($this->writeLogKey) ? $this->writeLogKey : ['key' => 'title,code', 'val' => '名称,编号']
        ];

        if ($type && isset($param['tableUniqueStr'])) {
            $data['editField'] = $this->tableCache->getModify('edit', $param['tableUniqueStr']);
        }
        return $data;
    }


    public static function getStatus(): array
    {
        return [0 => '禁用', 1 => '开启'];
    }


    /**
     * 验证数据
     * @access protected
     * @param array $data 数据
     * @param string|array $validate 验证器名或者验证规则数组
     * @param array $message 提示信息
     * @param bool $batch 是否批量验证
     * @return array|string|true
     * @throws ValidateException
     */
    protected function validate(array $data, $validate, array $message = [], bool $batch = false)
    {
        if (is_array($validate)) {
            $v = new Validate();
            $v->rule($validate);
        } else {
            if (strpos($validate, '.')) {
                // 支持场景
                [$validate, $scene] = explode('.', $validate);
            }
            $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
            $v = new $class();
            if (!empty($scene)) {
                $v->scene($scene);
            }
        }

        $v->message($message);

        // 是否批量验证
        if ($batch || $this->batchValidate) {
            $v->batch(true);
        }

        return $v->failException(true)->check($data);
    }

    protected function allowVerify()
    {
        if (request()->admin->id != 1) {
            if (!request()->admin->is_lock) return false;
        }
        return true;
    }

    protected function error($msg = '', string $url = null, $data = '', int $wait = 86400, array $header = []): Response
    {
        if (is_null($url)) {
            $url = request()->isAjax() ? '' : 'javascript:history.back(-1);';
        } elseif ($url) {
            $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : app('route')->buildUrl($url);
        }

        $result = [
            'code' => 0,
            'msg'  => $msg,
            'data' => $data,
            'url'  => $url,
            'wait' => $wait,
        ];

        $type = (request()->isJson() || request()->isAjax()) ? 'json' : 'html';

        // 所有form返回的都必须是json，所有A链接返回的都必须是Html
        $type = request()->isGet() ? 'html' : $type;

        if ($type == 'html') {
            $response = view((string)app('config')->get('app.dispatch_error_tmpl'), $result);
        } else if ($type == 'json') {
            $response = json($result);
        }

        throw new HttpResponseException($response);

    }


    public function __call($name, $arguments)
    {
        return View::fetch(app()->getBasePath() . '/error/empty.html', [
            'msg' => '' . $this->request->controller() . '控制器下方法' . $name . '不存在',
        ]);
    }

}
